﻿using System;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace ChinaTokenDev.Logger
{
    /// <summary>
    /// 文本类日志处理器
    /// </summary>
    public class TxtLogHelper : ILogAdapter
    {
        /// <summary>
        /// 日志文件存储根目录
        /// </summary>
        public string LogRootDir { get { return "Logs"; } }

        private readonly string DefaultLogName = "SysMonitor.log";

        ReaderWriterLockSlim _logWriteLock = new ReaderWriterLockSlim();
        /// <summary>
        /// 本地日志输出
        /// </summary>
        /// <param name="fileName">日志文件名（含全路径）</param>
        /// <param name="msg">日志内容</param>
        public void WriteLogEx(string fileName, string msg)
        {
            try
            {
                _logWriteLock.EnterWriteLock();
                FileMode runMode = File.Exists(fileName) ? FileMode.Append : FileMode.Create;
                //使用FileShare.ReadWrite属性可解决多线程时，写入日志同时有读取线程导致报异常问题
                //System.IO.IOException: 文件“xxxxxx”正由另一进程使用，因此该进程无法访问此文件。
                using (FileStream fs = new FileStream(fileName, runMode, FileAccess.Write, FileShare.ReadWrite))
                {
                    fs.Lock(0, msg.Length + 24);

                    using (StreamWriter sw = new StreamWriter(fs))
                    {
                        //格式： 日志输出时间 当前线程编号 消息体[日志类型 + 日志内容]
                        sw.WriteLine(string.Format("{0} {1} {2}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff").PadRight(2), Thread.CurrentThread.ManagedThreadId.ToString().PadRight(2), msg));
                        fs.Unlock(0, msg.Length + 24);//一定要用在Flush()方法以前，否则抛出异常。
                        sw.Flush();
                        sw.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                //日志写失败时则抛出异常
                Trace.WriteLine(ex.ToString());
                OutExceptionMessage(ex);
                //throw ex;
            }
            finally
            {
                _logWriteLock.ExitWriteLock();
            }
        }
        /// <summary>
        /// 创建日志默认目录
        /// </summary>
        private void CreateLogDirectory()
        {
            try
            {
                if (!Directory.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LogRootDir)))
                {
                    Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LogRootDir));
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 输出异常消息
        /// </summary>
        /// <param name="ex"></param>
        private void OutExceptionMessage(Exception ex)
        {
            CreateLogDirectory();

            string outFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, LogRootDir, DefaultLogName);
            string msg = string.Format("{0} {1} {2} {3}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff").PadRight(2), Thread.CurrentThread.ManagedThreadId.ToString().PadRight(2), "[ERROR]", ex.ToString());
            using (FileStream fs = new FileStream(outFileName, FileMode.Create, FileAccess.Write))
            {
                fs.Lock(0, msg.Length + 24);

                using (StreamWriter sw = new StreamWriter(fs))
                {
                    //格式： 日志输出时间 当前线程编号 消息体[日志类型 + 日志内容]
                    sw.WriteLine(string.Format("{0} {1} {2}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff").PadRight(2), Thread.CurrentThread.ManagedThreadId.ToString().PadRight(2), msg));
                    fs.Unlock(0, msg.Length + 24);//一定要用在Flush()方法以前，否则抛出异常。
                    sw.Flush();
                    sw.Close();
                }
            }
        }

        /// <summary>
        /// 输出调试信息
        /// </summary>
        /// <param name="name">日志文件名</param>
        /// <param name="msg">日志消息体</param>
        public void WriteDebugLog(string name, string msg)
        {
            WriteLogEx(string.IsNullOrWhiteSpace(name) ? DefaultLogName : name, string.Concat("[DEBUG] ".ToString().PadRight(2), msg));
        }

        /// <summary>
        /// 输出错误信息
        /// </summary>
        /// <param name="name">日志文件名</param>
        /// <param name="msg">日志消息体</param>
        public void WriteErrLog(string name, string msg)
        {
            WriteLogEx(string.IsNullOrWhiteSpace(name) ? DefaultLogName : name, string.Concat("[ERROR] ".ToString().PadRight(2), msg));
        }

        /// <summary>
        /// 输出普通信息
        /// </summary>
        /// <param name="name">日志文件名</param>
        /// <param name="msg">日志消息体</param>
        public void WriteInfoLog(string name, string msg)
        {
            WriteLogEx(string.IsNullOrWhiteSpace(name) ? DefaultLogName : name, string.Concat("[INFO] ".PadRight(2), msg));
        }

        /// <summary>
        /// 输出告警信息
        /// </summary>
        /// <param name="name">日志文件名</param>
        /// <param name="msg">日志消息体</param>
        public void WriteWarnLog(string name, string msg)
        {
            WriteLogEx(string.IsNullOrWhiteSpace(name) ? DefaultLogName : name, string.Concat("[WARN] ".PadRight(2), msg));
        }
    }
}
